package com.lovi.search.listener;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.lovi.clients.ProductClient;
import com.lovi.doc.ProductDoc;
import com.lovi.pojo.Product;
import lombok.extern.slf4j.Slf4j;
import org.elasticsearch.action.admin.indices.create.CreateIndexRequest;
import org.elasticsearch.action.bulk.BulkRequest;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.client.indices.GetIndexRequest;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.index.reindex.DeleteByQueryRequest;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.stereotype.Component;

import java.util.List;

/**
 * 监听搜索服务的启动，
 * 搜索服务一启动，我们就需要进行数据库的数据库同步。【前提把索引弄好】
 * 数据同步也就是把商品服务的数据拿过来，搞到es库里边【es库的初始化工作就搞定了】
 */
@Slf4j
@Component
public class ApplicationRunListener implements ApplicationRunner {
    //引入es客户端
    @Autowired
    private RestHighLevelClient client;
    //引入商品客户端
    @Autowired
    private ProductClient productClient;
    //引入product的查询索引参数
    private String createIndex = "{\n" +
            "  \"mappings\": {\n" +
            "    \"properties\": {\n" +
            "      \"productId\":{\n" +
            "        \"type\": \"integer\"\n" +
            "      },\n" +
            "      \"productName\":{\n" +
            "        \"type\": \"text\",\n" +
            "        \"analyzer\": \"ik_smart\",\n" +
            "        \"copy_to\": \"all\"\n" +
            "      },\n" +
            "      \"categoryId\":{\n" +
            "        \"type\": \"integer\"\n" +
            "      },\n" +
            "      \"productTitle\":{\n" +
            "        \"type\": \"text\",\n" +
            "        \"analyzer\": \"ik_smart\",\n" +
            "        \"copy_to\": \"all\"\n" +
            "      },\n" +
            "      \"productIntro\":{\n" +
            "        \"type\":\"text\",\n" +
            "        \"analyzer\": \"ik_smart\",\n" +
            "        \"copy_to\": \"all\"\n" +
            "      },\n" +
            "      \"productPicture\":{\n" +
            "        \"type\": \"keyword\",\n" +
            "        \"index\": false\n" +
            "      },\n" +
            "      \"productPrice\":{\n" +
            "        \"type\": \"double\",\n" +
            "        \"index\": true\n" +
            "      },\n" +
            "      \"productSellingPrice\":{\n" +
            "        \"type\": \"double\"\n" +
            "      },\n" +
            "      \"productNum\":{\n" +
            "        \"type\": \"integer\"\n" +
            "      },\n" +
            "      \"productSales\":{\n" +
            "        \"type\": \"integer\"\n" +
            "      },\n" +
            "      \"all\":{\n" +
            "        \"type\": \"text\",\n" +
            "        \"analyzer\": \"ik_max_word\"\n" +
            "      }\n" +
            "    }\n" +
            "  }\n" +
            "}";
    @Override
    public void run(ApplicationArguments args) throws Exception {
        log.info("ApplicationRunListener.run 结果为->{}", "测试搜索服务");


        /**
         * 1. 索引的创建，如果之前有索引，就不用管咯
         * 如果之前没有索引，我们就直接创建新的索引
         */
        //判断是否存在product索引
        GetIndexRequest getIndexRequest = new GetIndexRequest("product");
        boolean exists = client.indices().exists(getIndexRequest, RequestOptions.DEFAULT);


        if (!exists){
            //不存在,创建新索引
            CreateIndexRequest createIndexRequest = new CreateIndexRequest("product");
            createIndexRequest.source(createIndex, XContentType.JSON);
            client.indices().create(createIndexRequest,RequestOptions.DEFAULT);
        }



        /**
         * 2. es库当中数据的处理
         * 不管咋样，初始化我们都是先删除掉全部数据，然后查询全部数据，做批量插入操作，这样就能实现数据同步
         * 说明：
         * 因为我们有模糊搜索，我们多了个all字段（标题商品名描述），所以用到了
         * productDoc结合es的某个方法进行批量的数据插入
         * 这样子数据同步就完成咯
         */

        //删除全部数据
        DeleteByQueryRequest deleteIndexRequest = new DeleteByQueryRequest("product");
        deleteIndexRequest.setQuery(QueryBuilders.matchAllQuery());
        client.deleteByQuery(deleteIndexRequest,RequestOptions.DEFAULT);

        //查询全部数据
        List<Product> list = productClient.list();

        //插入全部数据
        BulkRequest bulkRequest = new BulkRequest();
        ObjectMapper objectMapper = new ObjectMapper();
        //对每个要插入product数据做处理，转换成需要的productDoc
        for (Product product : list) {
            ProductDoc productDoc = new ProductDoc(product);

            //构建Bulk请求：为Elasticsearch的批量索引操作添加一项任务，将productDoc对象作为一个新的JSON文档
            // 放入到"product"索引中，并且文档的ID是productDoc对象中的productId字段转换成的字符串形式。
            bulkRequest.add(new IndexRequest("product")
                    .id(productDoc.getProductId().toString())
                    .source(objectMapper.writeValueAsString(productDoc),XContentType.JSON));
        }

        //执行批量插入操作（实现数据同步）
        client.bulk(bulkRequest,RequestOptions.DEFAULT);
        log.info("ApplicationRunListener.run 结果为->{}", "es数据同步已完成！");


    }
}
